package org.asiainfo.system.controller;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import org.asiainfo.common.core.utils.StreamUtils;
import org.asiainfo.common.core.utils.StringUtils;
import org.asiainfo.common.idempotent.annotation.RepeatSubmit;
import org.asiainfo.common.log.annotation.Log;
import org.asiainfo.common.log.enums.BusinessType;
import org.asiainfo.common.satoken.utils.LoginHelper;
import org.asiainfo.common.tenant.utils.TenantHelper;
import org.asiainfo.system.api.model.LoginUser;
import org.asiainfo.system.domain.bo.SysDeptBo;
import org.asiainfo.system.domain.vo.SysRoleVo;
import org.asiainfo.system.domain.vo.SysUserInfoVo;
import org.asiainfo.system.domain.vo.UserInfoVo;
import org.asiainfo.system.service.SysDeptService;
import org.asiainfo.system.service.SysRoleService;
import org.asiainfo.system.service.SysTenantService;
import org.springframework.validation.annotation.Validated;
import org.asiainfo.system.service.SysUserService;
import org.asiainfo.system.domain.vo.SysUserVo;
import org.asiainfo.system.domain.bo.SysUserBo;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.asiainfo.common.mybatis.stream.core.page.PageQuery;
import org.asiainfo.common.mybatis.stream.core.page.TableDataInfo;
import org.asiainfo.common.core.domain.R;
import org.asiainfo.common.web.core.BaseController;
import jakarta.validation.constraints.*;
import org.asiainfo.common.core.validate.AddGroup;
import org.asiainfo.common.core.validate.EditGroup;

import java.util.List;

/**
 * 用户信息表
 *
 * @author dotor-ww
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/user")
public class SysUserController extends BaseController {

    private final SysUserService sysUserService;

    private final SysRoleService sysRoleService;

    private final SysDeptService sysDeptService;

    private final SysTenantService sysTenantService;

    /**
     * 分页查询
     *
     * @param sysUserBo 筛选条件
     * @param pageQuery 分页对象
     * @return 查询结果
     */
    @SaCheckPermission("system:user:list")
    @GetMapping("/list")
    public TableDataInfo<SysUserVo> list(SysUserBo sysUserBo, PageQuery pageQuery) {
        return sysUserService.queryPageList(sysUserBo, pageQuery);
    }

    /**
     * 通过主键查询单条数据
     *
     * @param userId 主键
     * @return 单条数据
     */
    @SaCheckPermission("system:user:query")
    @GetMapping({"/", "/{userId}"})
    public R<Object> getInfo(@PathVariable(value = "userId", required = false) Long userId) {
        // 校验用户是否有权限
        sysUserService.checkUserDateScope(userId);
        return R.ok(sysUserService.selectUserInfoByUserId(userId));
    }

    /**
     * 通过主键数组查询多条数据
     *
     * @param userIds 主键
     * @return 单条数据
     */
    @SaCheckPermission("system:user:query")
    @GetMapping("/getUserInfoByIds/{userIds}")
    public R<Object> getInfo(@PathVariable(value = "userIds", required = false) Long[] userIds) {
        // 校验用户是否有权限
        sysUserService.checkUserDateScope(LoginHelper.getUserId());
        return R.ok(sysUserService.selectUserByIds(userIds, null));
    }

    /**
     * 获取用户信息
     *
     * @return 用户信息
     */
    @GetMapping("/getInfo")
    public R<Object> getInfo() {
        LoginUser loginUser = LoginHelper.getLoginUser();
        SysUserVo sysUserVo = sysUserService.selectUserId(loginUser.getUserId());
        if (ObjectUtil.isNull(sysUserVo)) {
            return R.fail("没有权限访问用户数据!");
        }
        sysUserVo.setRoles(sysRoleService.selectRolesByUserId(loginUser.getUserId()));
        UserInfoVo userInfoVo = new UserInfoVo(sysUserVo, loginUser.getMenuPermission(), loginUser.getRolePermission());
        return R.ok(userInfoVo);
    }

    /**
     * 新增数据
     *
     * @param sysUserBo 实体
     * @return 新增结果
     */
    @SaCheckPermission("system:user:add")
    @Log(title = "用户管理", businessType = BusinessType.INSERT)
    @RepeatSubmit
    @PostMapping
    public R<Void> add(@Validated(AddGroup.class) @RequestBody SysUserBo sysUserBo) {
        sysDeptService.checkDeptDataScope(sysUserBo.getDeptId());
        if (sysUserService.checkUserNameUnique(sysUserBo)) {
            return R.fail("新增用户'" + sysUserBo.getUserName() + "'失败，登录账号已存在");
        } else if (StringUtils.isNotEmpty(sysUserBo.getPhoneNumber()) && sysUserService.checkPhoneUnique(sysUserBo)) {
            return R.fail("新增用户'" + sysUserBo.getUserName() + "'失败，手机号码已存在");
        } else if (StringUtils.isNotEmpty(sysUserBo.getEmail()) && sysUserService.checkEmailUnique(sysUserBo)) {
            return R.fail("新增用户'" + sysUserBo.getUserName() + "'失败，邮箱账号已存在");
        }
        // 新增用户判断租户人数
        if (TenantHelper.isEnable()) {
            if (!sysTenantService.checkAccountBalance(TenantHelper.getTenantId())) {
                return R.fail("当前租户下用户数量不足，请联系管理员");
            }
        }
        // 加密密码
        sysUserBo.setPassword(BCrypt.hashpw(sysUserBo.getPassword()));
        return toAjax(sysUserService.insertByBo(sysUserBo));
    }

    /**
     * 编辑数据
     *
     * @param sysUserBo 实体
     * @return 编辑结果
     */
    @SaCheckPermission("system:user:edit")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @RepeatSubmit
    @PutMapping
    public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysUserBo sysUserBo) {
        sysUserService.checkUserAllowed(sysUserBo.getUserId());
        sysUserService.checkUserDateScope(sysUserBo.getUserId());
        sysDeptService.checkDeptDataScope(sysUserBo.getDeptId());

        if (sysUserService.checkUserNameUnique(sysUserBo)) {
            return R.fail("修改用户'" + sysUserBo.getUserName() + "'失败，登录账号已存在");
        } else if (StringUtils.isNotEmpty(sysUserBo.getPhoneNumber()) && sysUserService.checkPhoneUnique(sysUserBo)) {
            return R.fail("修改用户'" + sysUserBo.getUserName() + "'失败，手机号码已存在");
        } else if (StringUtils.isNotEmpty(sysUserBo.getEmail()) && sysUserService.checkEmailUnique(sysUserBo)) {
            return R.fail("修改用户'" + sysUserBo.getUserName() + "'失败，邮箱账号已存在");
        }

        return toAjax(sysUserService.updateByBo(sysUserBo));
    }

    /**
     * 删除数据
     *
     * @param userIds 主键
     * @return 删除是否成功
     */
    @SaCheckPermission("system:user:remove")
    @Log(title = "用户管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{userIds}")
    public R<Void> remove(@NotEmpty(message = "用户ID不能为空") @PathVariable Long[] userIds) {
        if (ArrayUtil.contains(userIds, LoginHelper.getUserId())) {
            return R.fail("当前用户不能删除");
        }
        return toAjax(sysUserService.deleteWithValidByIds(List.of(userIds)));
    }

    /**
     * 根据用户ID批量获取用户信息
     *
     * @param userIds 用户ID组
     * @param deptId  部门ID
     * @return 查询结果
     */
    @SaCheckPermission("system:user:query")
    @GetMapping("/optionSelect")
    public R<Object> optionSelect(@RequestParam(required = false) Long[] userIds, @RequestParam(required = false) Long deptId) {
        return R.ok(sysUserService.selectUserByIds(userIds, deptId));
    }

    /**
     * 重置用户密码
     *
     * @param sysUserBo 用户信息
     * @return 操作结果
     */
    @SaCheckPermission("system:user:resetPwd")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping("/resetPwd")
    public R<Void> resetPwd(@RequestBody SysUserBo sysUserBo) {
        sysUserService.checkUserAllowed(sysUserBo.getUserId());
        sysUserService.checkUserDateScope(sysUserBo.getUserId());
        return toAjax(sysUserService.resetUserPwd(sysUserBo.getUserId(), BCrypt.hashpw(sysUserBo.getPassword())));
    }

    /**
     * 更新用户状态
     *
     * @param sysUserBo 用户信息
     * @return 操作结果
     */
    @SaCheckPermission("system:user:edit")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @RepeatSubmit
    @PutMapping("/changeUserStatus")
    public R<Void> changeUserStatus(@Validated(EditGroup.class) @RequestBody SysUserBo sysUserBo) {
        sysUserService.checkUserAllowed(sysUserBo.getUserId());
        sysUserService.checkUserDateScope(sysUserBo.getUserId());
        return toAjax(sysUserService.updateUserStatus(sysUserBo));
    }

    /**
     * 根据用户ID查询角色
     *
     * @param userId 用户ID
     * @return 查询结果
     */
    @SaCheckPermission("system:user:query")
    @GetMapping("/authRole/{userId}")
    public R<Object> authRoleByUserId(@NotEmpty(message = "用户ID不能为空") @PathVariable Long userId) {
        sysUserService.checkUserDateScope(userId);
        SysUserVo sysUserVo = sysUserService.selectUserId(userId);
        List<SysRoleVo> sysRoleVos = sysRoleService.selectRolesAuthByUserId(userId);
        SysUserInfoVo sysUserInfoVo = new SysUserInfoVo();
        sysUserInfoVo.setSysUserVo(sysUserVo);
        sysUserInfoVo.setRoles(LoginHelper.isSuperAdmin(userId) ? sysRoleVos : StreamUtils.filter(sysRoleVos, r -> !r.isSuperAdmin()));
        return R.ok(sysUserInfoVo);
    }

    /**
     * 用户授权角色
     *
     * @param userId  用户ID
     * @param roleIds 角色组
     * @return 操作结果
     */
    @SaCheckPermission("system:user:edit")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping("/authRole")
    public R<Void> insertAuthRole(Long userId, Long[] roleIds) {
        sysUserService.checkUserDateScope(userId);
        sysUserService.insertUserAuth(userId, roleIds);
        return R.ok();
    }

    /**
     * 获取部门下的所有用户信息
     *
     * @param deptId 部门ID
     * @return 结果
     */
    @SaCheckPermission("system:user:list")
    @GetMapping("/list/dept/{deptId}")
    public R<Object> listByDeptId(@NotNull(message = "部门ID不能为空") @PathVariable Long deptId) {
        return R.ok(sysUserService.selectUserListByDeptId(deptId));
    }

    /**
     * 获取部门树列表
     *
     * @param sysDeptBo 部门信息
     * @return 部门树列表
     */
    @SaCheckPermission("system:user:list")
    @GetMapping("/deptTree")
    public R<Object> deptTree(SysDeptBo sysDeptBo) {
        return R.ok(sysDeptService.selectDeptTree(sysDeptBo));
    }
}
